1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package com.sun.java.util.jar.pack;
27
28 import java.io.IOException;
29 import java.util.Arrays;
30 import static com.sun.java.util.jar.pack.Constants.*;
31
32
33
34
35
36
37 class Instruction {
38 protected byte[] bytes;
39 protected int pc;
40 protected int bc;
41 protected int w;
42 protected int length;
43
44 protected boolean special;
45
46 protected Instruction(byte[] bytes, int pc, int bc, int w, int length) {
47 reset(bytes, pc, bc, w, length);
48 }
49 private void reset(byte[] bytes, int pc, int bc, int w, int length) {
50 this.bytes = bytes;
51 this.pc = pc;
52 this.bc = bc;
53 this.w = w;
54 this.length = length;
55 }
56
57 public int getBC() {
58 return bc;
59 }
60 public boolean isWide() {
61 return w != 0;
62 }
63 public byte[] getBytes() {
64 return bytes;
65 }
66 public int getPC() {
67 return pc;
68 }
69 public int getLength() {
70 return length;
71 }
72 public int getNextPC() {
73 return pc + length;
74 }
75
76 public Instruction next() {
77 int npc = pc + length;
78 if (npc == bytes.length)
79 return null;
80 else
81 return Instruction.at(bytes, npc, this);
82 }
83
84 public boolean isNonstandard() {
85 return isNonstandard(bc);
86 }
87
88 public void setNonstandardLength(int length) {
89 assert(isNonstandard());
90 this.length = length;
91 }
92
93
94
95 public Instruction forceNextPC(int nextpc) {
96 int llength = nextpc - pc;
97 return new Instruction(bytes, pc, -1, -1, llength);
98 }
99
100 public static Instruction at(byte[] bytes, int pc) {
101 return Instruction.at(bytes, pc, null);
102 }
103
104 public static Instruction at(byte[] bytes, int pc, Instruction reuse) {
105 int bc = getByte(bytes, pc);
106 int prefix = -1;
107 int w = 0;
108 int length = BC_LENGTH[w][bc];
109 if (length == 0) {
110
111 switch (bc) {
112 case _wide:
113 bc = getByte(bytes, pc+1);
114 w = 1;
115 length = BC_LENGTH[w][bc];
116 if (length == 0) {
117
118 length = 1;
119 }
120 break;
121 case _tableswitch:
122 return new TableSwitch(bytes, pc);
123 case _lookupswitch:
124 return new LookupSwitch(bytes, pc);
125 default:
126
127 length = 1;
128 break;
129 }
130 }
131 assert(length > 0);
132 assert(pc+length <= bytes.length);
133
134 if (reuse != null && !reuse.special) {
135 reuse.reset(bytes, pc, bc, w, length);
136 return reuse;
137 }
138 return new Instruction(bytes, pc, bc, w, length);
139 }
140
141
142 public byte getCPTag() {
143 return BC_TAG[w][bc];
144 }
145
146
147 public int getCPIndex() {
148 int indexLoc = BC_INDEX[w][bc];
149 if (indexLoc == 0) return -1;
150 assert(w == 0);
151 if (length == 2)
152 return getByte(bytes, pc+indexLoc);
153 else
154 return getShort(bytes, pc+indexLoc);
155 }
156
157 public void setCPIndex(int cpi) {
158 int indexLoc = BC_INDEX[w][bc];
159 assert(indexLoc != 0);
160 if (length == 2)
161 setByte(bytes, pc+indexLoc, cpi);
162 else
163 setShort(bytes, pc+indexLoc, cpi);
164 assert(getCPIndex() == cpi);
165 }
166
167 public ConstantPool.Entry getCPRef(ConstantPool.Entry[] cpMap) {
168 int index = getCPIndex();
169 return (index < 0) ? null : cpMap[index];
170 }
171
172
173 public int getLocalSlot() {
174 int slotLoc = BC_SLOT[w][bc];
175 if (slotLoc == 0) return -1;
176 if (w == 0)
177 return getByte(bytes, pc+slotLoc);
178 else
179 return getShort(bytes, pc+slotLoc);
180 }
181
182
183 public int getBranchLabel() {
184 int branchLoc = BC_BRANCH[w][bc];
185 if (branchLoc == 0) return -1;
186 assert(w == 0);
187 assert(length == 3 || length == 5);
188 int offset;
189 if (length == 3)
190 offset = (short)getShort(bytes, pc+branchLoc);
191 else
192 offset = getInt(bytes, pc+branchLoc);
193 assert(offset+pc >= 0);
194 assert(offset+pc <= bytes.length);
195 return offset+pc;
196 }
197
198 public void setBranchLabel(int targetPC) {
199 int branchLoc = BC_BRANCH[w][bc];
200 assert(branchLoc != 0);
201 if (length == 3)
202 setShort(bytes, pc+branchLoc, targetPC-pc);
203 else
204 setInt(bytes, pc+branchLoc, targetPC-pc);
205 assert(targetPC == getBranchLabel());
206 }
207
208
209
210 public int getConstant() {
211 int conLoc = BC_CON[w][bc];
212 if (conLoc == 0) return 0;
213 switch (length - conLoc) {
214 case 1: return (byte) getByte(bytes, pc+conLoc);
215 case 2: return (short) getShort(bytes, pc+conLoc);
216 }
217 assert(false);
218 return 0;
219 }
220
221 public void setConstant(int con) {
222 int conLoc = BC_CON[w][bc];
223 assert(conLoc != 0);
224 switch (length - conLoc) {
225 case 1: setByte(bytes, pc+conLoc, con); break;
226 case 2: setShort(bytes, pc+conLoc, con); break;
227 }
228 assert(con == getConstant());
229 }
230
231 public abstract static class Switch extends Instruction {
232
233 public abstract int getCaseCount();
234 public abstract int getCaseValue(int n);
235 public abstract int getCaseLabel(int n);
236 public abstract void setCaseCount(int caseCount);
237 public abstract void setCaseValue(int n, int value);
238 public abstract void setCaseLabel(int n, int targetPC);
239 protected abstract int getLength(int caseCount);
240
241 public int getDefaultLabel() { return intAt(0)+pc; }
242 public void setDefaultLabel(int targetPC) { setIntAt(0, targetPC-pc); }
243
244 protected int apc;
245 protected int intAt(int n) { return getInt(bytes, apc + n*4); }
246 protected void setIntAt(int n, int x) { setInt(bytes, apc + n*4, x); }
247 protected Switch(byte[] bytes, int pc, int bc) {
248 super(bytes, pc, bc, 0, 0);
249 this.apc = alignPC(pc+1);
250 this.special = true;
251 length = getLength(getCaseCount());
252 }
253 public int getAlignedPC() { return apc; }
254 public String toString() {
255 String s = super.toString();
256 s += " Default:"+labstr(getDefaultLabel());
257 int caseCount = getCaseCount();
258 for (int i = 0; i < caseCount; i++) {
259 s += "\n\tCase "+getCaseValue(i)+":"+labstr(getCaseLabel(i));
260 }
261 return s;
262 }
263 public static int alignPC(int apc) {
264 while (apc % 4 != 0) ++apc;
265 return apc;
266 }
267 }
268
269 public static class TableSwitch extends Switch {
270
271 public int getLowCase() { return intAt(1); }
272 public int getHighCase() { return intAt(2); }
273 public int getCaseCount() { return intAt(2)-intAt(1)+1; }
274 public int getCaseValue(int n) { return getLowCase()+n; }
275 public int getCaseLabel(int n) { return intAt(3+n)+pc; }
276
277 public void setLowCase(int val) { setIntAt(1, val); }
278 public void setHighCase(int val) { setIntAt(2, val); }
279 public void setCaseLabel(int n, int tpc) { setIntAt(3+n, tpc-pc); }
280 public void setCaseCount(int caseCount) {
281 setHighCase(getLowCase() + caseCount - 1);
282 length = getLength(caseCount);
283 }
284 public void setCaseValue(int n, int val) {
285 if (n != 0) throw new UnsupportedOperationException();
286 int caseCount = getCaseCount();
287 setLowCase(val);
288 setCaseCount(caseCount);
289 }
290
291 TableSwitch(byte[] bytes, int pc) {
292 super(bytes, pc, _tableswitch);
293 }
294 protected int getLength(int caseCount) {
295 return (apc-pc) + (3 + caseCount) * 4;
296 }
297 }
298
299 public static class LookupSwitch extends Switch {
300
301 public int getCaseCount() { return intAt(1); }
302 public int getCaseValue(int n) { return intAt(2+n*2+0); }
303 public int getCaseLabel(int n) { return intAt(2+n*2+1)+pc; }
304
305 public void setCaseCount(int caseCount) {
306 setIntAt(1, caseCount);
307 length = getLength(caseCount);
308 }
309 public void setCaseValue(int n, int val) { setIntAt(2+n*2+0, val); }
310 public void setCaseLabel(int n, int tpc) { setIntAt(2+n*2+1, tpc-pc); }
311
312 LookupSwitch(byte[] bytes, int pc) {
313 super(bytes, pc, _lookupswitch);
314 }
315 protected int getLength(int caseCount) {
316 return (apc-pc) + (2 + caseCount*2) * 4;
317 }
318 }
319
320
321 public boolean equals(Object o) {
322 return (o != null) && (o.getClass() == Instruction.class)
323 && equals((Instruction) o);
324 }
325
326 public int hashCode() {
327 int hash = 3;
328 hash = 11 * hash + Arrays.hashCode(this.bytes);
329 hash = 11 * hash + this.pc;
330 hash = 11 * hash + this.bc;
331 hash = 11 * hash + this.w;
332 hash = 11 * hash + this.length;
333 return hash;
334 }
335
336 public boolean equals(Instruction that) {
337 if (this.pc != that.pc) return false;
338 if (this.bc != that.bc) return false;
339 if (this.w != that.w) return false;
340 if (this.length != that.length) return false;
341 for (int i = 1; i < length; i++) {
342 if (this.bytes[this.pc+i] != that.bytes[that.pc+i])
343 return false;
344 }
345 return true;
346 }
347
348 static String labstr(int pc) {
349 if (pc >= 0 && pc < 100000)
350 return ((100000+pc)+"").substring(1);
351 return pc+"";
352 }
353 public String toString() {
354 return toString(null);
355 }
356 public String toString(ConstantPool.Entry[] cpMap) {
357 String s = labstr(pc) + ": ";
358 if (bc >= _bytecode_limit) {
359 s += Integer.toHexString(bc);
360 return s;
361 }
362 if (w == 1) s += "wide ";
363 String bcname = (bc < BC_NAME.length)? BC_NAME[bc]: null;
364 if (bcname == null) {
365 return s+"opcode#"+bc;
366 }
367 s += bcname;
368 int tag = getCPTag();
369 if (tag != 0) s += " "+ConstantPool.tagName(tag)+":";
370 int idx = getCPIndex();
371 if (idx >= 0) s += (cpMap == null) ? ""+idx : "="+cpMap[idx].stringValue();
372 int slt = getLocalSlot();
373 if (slt >= 0) s += " Local:"+slt;
374 int lab = getBranchLabel();
375 if (lab >= 0) s += " To:"+labstr(lab);
376 int con = getConstant();
377 if (con != 0) s += " Con:"+con;
378 return s;
379 }
380
381
382
383
384
385
386 public int getIntAt(int off) {
387 return getInt(bytes, pc+off);
388 }
389 public int getShortAt(int off) {
390 return getShort(bytes, pc+off);
391 }
392 public int getByteAt(int off) {
393 return getByte(bytes, pc+off);
394 }
395
396
397 public static int getInt(byte[] bytes, int pc) {
398 return (getShort(bytes, pc+0) << 16) + (getShort(bytes, pc+2) << 0);
399 }
400 public static int getShort(byte[] bytes, int pc) {
401 return (getByte(bytes, pc+0) << 8) + (getByte(bytes, pc+1) << 0);
402 }
403 public static int getByte(byte[] bytes, int pc) {
404 return bytes[pc] & 0xFF;
405 }
406
407
408 public static void setInt(byte[] bytes, int pc, int x) {
409 setShort(bytes, pc+0, x >> 16);
410 setShort(bytes, pc+2, x >> 0);
411 }
412 public static void setShort(byte[] bytes, int pc, int x) {
413 setByte(bytes, pc+0, x >> 8);
414 setByte(bytes, pc+1, x >> 0);
415 }
416 public static void setByte(byte[] bytes, int pc, int x) {
417 bytes[pc] = (byte)x;
418 }
419
420
421
422
423 public static boolean isNonstandard(int bc) {
424 return BC_LENGTH[0][bc] < 0;
425 }
426
427 public static int opLength(int bc) {
428 int l = BC_LENGTH[0][bc];
429 assert(l > 0);
430 return l;
431 }
432 public static int opWideLength(int bc) {
433 int l = BC_LENGTH[1][bc];
434 assert(l > 0);
435 return l;
436 }
437
438 public static boolean isLocalSlotOp(int bc) {
439 return (bc < BC_SLOT[0].length && BC_SLOT[0][bc] > 0);
440 }
441
442 public static boolean isBranchOp(int bc) {
443 return (bc < BC_BRANCH[0].length && BC_BRANCH[0][bc] > 0);
444 }
445
446 public static boolean isCPRefOp(int bc) {
447 if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0) return true;
448 if (bc >= _xldc_op && bc < _xldc_limit) return true;
449 return false;
450 }
451
452 public static byte getCPRefOpTag(int bc) {
453 if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0) return BC_TAG[0][bc];
454 if (bc >= _xldc_op && bc < _xldc_limit) return CONSTANT_Literal;
455 return CONSTANT_None;
456 }
457
458 public static boolean isFieldOp(int bc) {
459 return (bc >= _getstatic && bc <= _putfield);
460 }
461
462 public static boolean isInvokeInitOp(int bc) {
463 return (bc >= _invokeinit_op && bc < _invokeinit_limit);
464 }
465
466 public static boolean isSelfLinkerOp(int bc) {
467 return (bc >= _self_linker_op && bc < _self_linker_limit);
468 }
469
470
471
472 static private final byte[][] BC_LENGTH = new byte[2][0x100];
473 static private final byte[][] BC_INDEX = new byte[2][0x100];
474 static private final byte[][] BC_TAG = new byte[2][0x100];
475 static private final byte[][] BC_BRANCH = new byte[2][0x100];
476 static private final byte[][] BC_SLOT = new byte[2][0x100];
477 static private final byte[][] BC_CON = new byte[2][0x100];
478 static private final String[] BC_NAME = new String[0x100];
479 static private final String[][] BC_FORMAT = new String[2][_bytecode_limit];
480 static {
481 for (int i = 0; i < _bytecode_limit; i++) {
482 BC_LENGTH[0][i] = -1;
483 BC_LENGTH[1][i] = -1;
484 }
485 def("b", _nop, _dconst_1);
486 def("bx", _bipush);
487 def("bxx", _sipush);
488 def("bk", _ldc);
489 def("bkk", _ldc_w, _ldc2_w);
490 def("blwbll", _iload, _aload);
491 def("b", _iload_0, _saload);
492 def("blwbll", _istore, _astore);
493 def("b", _istore_0, _lxor);
494 def("blxwbllxx", _iinc);
495 def("b", _i2l, _dcmpg);
496 def("boo", _ifeq, _jsr);
497 def("blwbll", _ret);
498 def("", _tableswitch, _lookupswitch);
499 def("b", _ireturn, _return);
500 def("bkf", _getstatic, _putfield);
501 def("bkm", _invokevirtual, _invokestatic);
502 def("bkixx", _invokeinterface);
503 def("", _xxxunusedxxx);
504 def("bkc", _new);
505 def("bx", _newarray);
506 def("bkc", _anewarray);
507 def("b", _arraylength, _athrow);
508 def("bkc", _checkcast, _instanceof);
509 def("b", _monitorenter, _monitorexit);
510 def("", _wide);
511 def("bkcx", _multianewarray);
512 def("boo", _ifnull, _ifnonnull);
513 def("boooo", _goto_w, _jsr_w);
514 for (int i = 0; i < _bytecode_limit; i++) {
515
516
517 if (BC_LENGTH[0][i] == -1) {
518 assert(i == _xxxunusedxxx);
519 continue;
520 }
521
522
523 if (BC_LENGTH[1][i] == -1)
524 BC_LENGTH[1][i] = (byte)(1+BC_LENGTH[0][i]);
525 }
526
527 String names =
528 "nop aconst_null iconst_m1 iconst_0 iconst_1 iconst_2 iconst_3 iconst_4 "+
529 "iconst_5 lconst_0 lconst_1 fconst_0 fconst_1 fconst_2 dconst_0 dconst_1 "+
530 "bipush sipush ldc ldc_w ldc2_w iload lload fload dload aload iload_0 "+
531 "iload_1 iload_2 iload_3 lload_0 lload_1 lload_2 lload_3 fload_0 fload_1 "+
532 "fload_2 fload_3 dload_0 dload_1 dload_2 dload_3 aload_0 aload_1 aload_2 "+
533 "aload_3 iaload laload faload daload aaload baload caload saload istore "+
534 "lstore fstore dstore astore istore_0 istore_1 istore_2 istore_3 lstore_0 "+
535 "lstore_1 lstore_2 lstore_3 fstore_0 fstore_1 fstore_2 fstore_3 dstore_0 "+
536 "dstore_1 dstore_2 dstore_3 astore_0 astore_1 astore_2 astore_3 iastore "+
537 "lastore fastore dastore aastore bastore castore sastore pop pop2 dup "+
538 "dup_x1 dup_x2 dup2 dup2_x1 dup2_x2 swap iadd ladd fadd dadd isub lsub "+
539 "fsub dsub imul lmul fmul dmul idiv ldiv fdiv ddiv irem lrem frem drem "+
540 "ineg lneg fneg dneg ishl lshl ishr lshr iushr lushr iand land ior lor "+
541 "ixor lxor iinc i2l i2f i2d l2i l2f l2d f2i f2l f2d d2i d2l d2f i2b i2c "+
542 "i2s lcmp fcmpl fcmpg dcmpl dcmpg ifeq ifne iflt ifge ifgt ifle if_icmpeq "+
543 "if_icmpne if_icmplt if_icmpge if_icmpgt if_icmple if_acmpeq if_acmpne "+
544 "goto jsr ret tableswitch lookupswitch ireturn lreturn freturn dreturn "+
545 "areturn return getstatic putstatic getfield putfield invokevirtual "+
546 "invokespecial invokestatic invokeinterface xxxunusedxxx new newarray "+
547 "anewarray arraylength athrow checkcast instanceof monitorenter "+
548 "monitorexit wide multianewarray ifnull ifnonnull goto_w jsr_w ";
549 for (int bc = 0; names.length() > 0; bc++) {
550 int sp = names.indexOf(' ');
551 BC_NAME[bc] = names.substring(0, sp);
552 names = names.substring(sp+1);
553 }
554 }
555 public static String byteName(int bc) {
556 String iname;
557 if (bc < BC_NAME.length && BC_NAME[bc] != null) {
558 iname = BC_NAME[bc];
559 } else if (isSelfLinkerOp(bc)) {
560 int idx = (bc - _self_linker_op);
561 boolean isSuper = (idx >= _self_linker_super_flag);
562 if (isSuper) idx -= _self_linker_super_flag;
563 boolean isAload = (idx >= _self_linker_aload_flag);
564 if (isAload) idx -= _self_linker_aload_flag;
565 int origBC = _first_linker_op + idx;
566 assert(origBC >= _first_linker_op && origBC <= _last_linker_op);
567 iname = BC_NAME[origBC];
568 iname += (isSuper ? "_super" : "_this");
569 if (isAload) iname = "aload_0&" + iname;
570 iname = "*"+iname;
571 } else if (isInvokeInitOp(bc)) {
572 int idx = (bc - _invokeinit_op);
573 switch (idx) {
574 case _invokeinit_self_option:
575 iname = "*invokespecial_init_this"; break;
576 case _invokeinit_super_option:
577 iname = "*invokespecial_init_super"; break;
578 default:
579 assert(idx == _invokeinit_new_option);
580 iname = "*invokespecial_init_new"; break;
581 }
582 } else {
583 switch (bc) {
584 case _ildc: iname = "*ildc"; break;
585 case _fldc: iname = "*fldc"; break;
586 case _ildc_w: iname = "*ildc_w"; break;
587 case _fldc_w: iname = "*fldc_w"; break;
588 case _dldc2_w: iname = "*dldc2_w"; break;
589 case _cldc: iname = "*cldc"; break;
590 case _cldc_w: iname = "*cldc_w"; break;
591 case _byte_escape: iname = "*byte_escape"; break;
592 case _ref_escape: iname = "*ref_escape"; break;
593 case _end_marker: iname = "*end"; break;
594 default: iname = "*bc#"+bc; break;
595 }
596 }
597 return iname;
598 }
599 private static int BW = 4;
600 private static void def(String fmt, int bc) {
601 def(fmt, bc, bc);
602 }
603 private static void def(String fmt, int from_bc, int to_bc) {
604 String[] fmts = { fmt, null };
605 if (fmt.indexOf('w') > 0) {
606 fmts[1] = fmt.substring(fmt.indexOf('w'));
607 fmts[0] = fmt.substring(0, fmt.indexOf('w'));
608 }
609 for (int w = 0; w <= 1; w++) {
610 fmt = fmts[w];
611 if (fmt == null) continue;
612 int length = fmt.length();
613 int index = Math.max(0, fmt.indexOf('k'));
614 int tag = CONSTANT_None;
615 int branch = Math.max(0, fmt.indexOf('o'));
616 int slot = Math.max(0, fmt.indexOf('l'));
617 int con = Math.max(0, fmt.indexOf('x'));
618 if (index > 0 && index+1 < length) {
619 switch (fmt.charAt(index+1)) {
620 case 'c': tag = CONSTANT_Class; break;
621 case 'k': tag = CONSTANT_Literal; break;
622 case 'f': tag = CONSTANT_Fieldref; break;
623 case 'm': tag = CONSTANT_Methodref; break;
624 case 'i': tag = CONSTANT_InterfaceMethodref; break;
625 }
626 assert(tag != CONSTANT_None);
627 } else if (index > 0 && length == 2) {
628 assert(from_bc == _ldc);
629 tag = CONSTANT_Literal;
630 }
631 for (int bc = from_bc; bc <= to_bc; bc++) {
632 BC_FORMAT[w][bc] = fmt;
633 assert(BC_LENGTH[w][bc] == -1);
634 BC_LENGTH[w][bc] = (byte) length;
635 BC_INDEX[w][bc] = (byte) index;
636 BC_TAG[w][bc] = (byte) tag;
637 assert(!(index == 0 && tag != CONSTANT_None));
638 BC_BRANCH[w][bc] = (byte) branch;
639 BC_SLOT[w][bc] = (byte) slot;
640 assert(branch == 0 || slot == 0);
641 assert(branch == 0 || index == 0);
642 assert(slot == 0 || index == 0);
643 BC_CON[w][bc] = (byte) con;
644 }
645 }
646 }
647
648 public static void opcodeChecker(byte[] code) throws FormatException {
649 Instruction i = at(code, 0);
650 while (i != null) {
651 int opcode = i.getBC();
652 if (opcode == _xxxunusedxxx || opcode < _nop || opcode > _jsr_w) {
653 String message = "illegal opcode: " + opcode + " " + i;
654 throw new FormatException(message);
655 }
656 i = i.next();
657 }
658 }
659 static class FormatException extends IOException {
660 FormatException(String message) {
661 super(message);
662 }
663 }
664 }